package pln.adnotation;

/*
 * @author Adrian Airinei
 */

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import pln.adnotation.application.LexicalChain;
import pln.adnotation.application.MetaChain;
import pln.adnotation.elkb.Index;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;


public class Adnote {

	private final static String STOP_WORDS_FILE = "stopwords.txt"; 
	private final static String XML_OUTPUT_FILE = "output.xml";
	private final static String CHAT_OUTPUT_FILE = "chat.txt";
	
	public static final String USER_DIR = System.getProperty("user.dir");
	public static final String INDEX = USER_DIR + "\\roget_elkb\\elkbIndex.dat";
    public static final String INDEX_FILE = USER_DIR + "\\roget_elkb\\newIndex.txt"; 
	
	private String xmlFileInput;
	private ArrayList<String> stopWordList;
	private List<Utterance> utt;
	private Document dom;
	
	public static void main(String []args)
	{
		Adnote ad; 
		
		if(args.length != 1)
		{
			System.out.println("Usage: adnotation.jar <xml_input_file>");
			System.exit(0);
		}
		System.out.println("Adnotation started.");
		
		ad = new Adnote(args[0]);
		
		// parse the input xml file			
		ad.parseXmlFile();
		
		System.out.println("Eliminating stop words...");
		ad.eliminateStopWords(); 
		System.out.println("Eliminating stop words ended.");
		
		System.out.println("Starting stemming...");
		ad.stem();
		System.out.println("Stemming finished.");
		
		System.out.println("Finding lexical chains...");
		ad.findLexicalChains();
		System.out.println("Lexical chains found.");
		
		System.out.println("Generate the xml resulted file...");
		ad.printToFile();
		System.out.println("xml file created.");
		
		System.out.println("Adnotation ended.");
	}
	
	public Adnote(String xmlFile)
	{
		this.xmlFileInput = xmlFile;
		this.stopWordList = new ArrayList<String>();
		this.utt = new ArrayList<Utterance>();
	}
	
   /******************************************************************
   * createIndex()
   ******************************************************************/
   private void createIndex() {
	   
	   System.out.println("\nCreate Roget's Index");
	   System.out.println("----------------------\n");
	   System.out.println("Creating the index. Please wait...\n");
	   try {

		   System.out.println(INDEX_FILE);
		   Index elkbIndex = new Index(INDEX_FILE, 125000);
		   
		   System.out.println("# of index items : " 
				   + elkbIndex.getItemCount());
		   System.out.println("# of references  : " 
				   + elkbIndex.getRefCount());
		   System.out.println("# of unique refs : "
				   + elkbIndex.getUniqRefCount());   
		   System.out.println("Items Map size   : " 
				   + elkbIndex.getItemsMapSize());
		   
		   System.out.println("\nSaving Index object. Please wait...");
		   
		   try {
			   ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(INDEX));
			   out.writeObject(elkbIndex);
			   out.close();
		   } catch(Exception e) {
			   e.printStackTrace();
		   }
	   }	catch(Exception e1) {
		   e1.printStackTrace();
	   }  	
	   
   } 

	public void findLexicalChains()
	{
		try{
			// output in a file the whole conversation
			BufferedWriter bw = new BufferedWriter(new FileWriter(new File(CHAT_OUTPUT_FILE)));
			//get the root element
			Element docEle = dom.getDocumentElement();
	
			//get a nodelist of  elements
			NodeList nl = docEle.getElementsByTagName("Utterance");
			if(nl != null && nl.getLength() > 0)
			{
				for(int i = 0 ; i < nl.getLength();i++)
				{
					//get the utterance element and write its text content into CHAT_OUTPUT_FILE
					Element el = (Element)nl.item(i);
					String value = new String(el.getTextContent());
					bw.write(value);
					bw.newLine();
				}
			}
			bw.close();
		}catch(Exception e){
			System.err.println("Error when writing the conversation to file "+CHAT_OUTPUT_FILE);
			System.err.println("Lexical chains could not be found!");
			return;
		}
		
		// detect the lexical chains
		createIndex();
		LexicalChain lc = new LexicalChain();
		
//		lc.setDebug(true);
		lc.setFileName(CHAT_OUTPUT_FILE);
//		lc.setScoreFunction("HIndex");
		lc.loadFile();
		
//		lc.printCandidateWords();   // only if debug is activated
		Collection chainSet = lc.buildLCFinal();  // outputs the chains to console

		// output them to the xml file
		Element chains = dom.createElement("LexicalChains");
		Element dialog = (Element)dom.getElementsByTagName("Dialog").item(0);
		dialog.appendChild(chains);
		
		ArrayList<MetaChain> chainList = new ArrayList<MetaChain>();
		MetaChain mc;
        Iterator iter = chainSet.iterator();
        int counter = 0;
        while (iter.hasNext())
        {
        	counter++;
        	mc = (MetaChain)iter.next();
        	chainList.add(mc);
//        	System.out.println(mc);
        	mc.printToXML(chains, dom, counter);
        }
        
        // detect the inference between the chains
        Element inferences = dom.createElement("ChainInferences");
		dialog.appendChild(inferences);
        
        // for each two different chains
             // if chain1 intersect with chain2  gives line x and (x==lineChain1 OR x==lineChain2)  ===> inference
        for(int i=0;i<chainList.size();i++)
        	for(int j=i+1;j<chainList.size();j++)
        	{
        		MetaChain mc1 = chainList.get(i);
        		MetaChain mc2 = chainList.get(j);
        		int lineIntersect = mc1.intersectChain(mc2, dom);
        		if(mc1.getStartLine() == lineIntersect)
        		{
        			// there is inference from chain j to chain i. Print it to XML output
        			System.out.println("inference from chain "+(j+1)+" to chain "+(i+1)+". See line "+lineIntersect);
        			Element inference = dom.createElement("Inference");
        			inference.setAttribute("FromChain", (j+1)+"");
        			inference.setAttribute("ToChain", (i+1)+"");
        			inference.setAttribute("Line", (lineIntersect)+"");
        			inferences.appendChild(inference);
        		}
        		else if(mc2.getStartLine() == lineIntersect)
        		{
        			// there is inference from chain i to chain j. Print it to XML output
        			System.out.println("inference from chain "+(i+1)+" to chain "+(j+1)+". See line "+lineIntersect);
        			Element inference = dom.createElement("Inference");
        			inference.setAttribute("FromChain", (i+1)+"");
        			inference.setAttribute("ToChain", (j+1)+"");
        			inference.setAttribute("Line", (lineIntersect)+"");
        			inferences.appendChild(inference);
        		}
        	}
        
	}
	
	public void stem()
	{
		Stemmer s = new Stemmer();
		
		//get the root element
		Element docEle = dom.getDocumentElement();

		//get a nodelist of  elements
		NodeList nl = docEle.getElementsByTagName("Utterance");
		if(nl != null && nl.getLength() > 0)
		{
			for(int i = 0 ; i < nl.getLength();i++)
			{
				//get the utterance element and stem its text content
				Element el = (Element)nl.item(i);
				String value = new String(el.getTextContent());
				el.setTextContent(s.stem(value));
			}
		}
	}
	
	public void eliminateStopWords()
	{
		try {
			BufferedReader stopWordsFile;
			String line;
			
			// extract the stop word list
			stopWordsFile = new BufferedReader(new FileReader(STOP_WORDS_FILE));
			line = stopWordsFile.readLine();
			while(line != null)
			{
				stopWordList.add(line);
				line = stopWordsFile.readLine();
			}
			stopWordsFile.close();
			
			parseDocumentAndRemoveStopWords();
			
		} catch (FileNotFoundException e) {
			System.err.println("Error: File not found: " + STOP_WORDS_FILE);
		} catch(IOException e)
		{
			System.err.println("Error: IOException");
			e.printStackTrace();
		}
	}
	
	private String removeStopWords(String input)
	{
		String result = new String(input);
		
		for(int i=0;i<stopWordList.size();i++)
		{
			result = result.replaceAll(" "+stopWordList.get(i)+" ", " ");
		}
		
		return result;
	}
	
	private void parseXmlFile()
	{
		//get the factory
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

		try {

			//Using factory get an instance of document builder
			DocumentBuilder db = dbf.newDocumentBuilder();

			//parse using builder to get DOM representation of the XML file
			dom = db.parse(xmlFileInput);

		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch(SAXException se) {
			se.printStackTrace();
		}catch(IOException ioe) {
			ioe.printStackTrace();
		}
	}
	
	private void parseDocumentAndRemoveStopWords(){
		//get the root element
		Element docEle = dom.getDocumentElement();

		//get a nodelist of  elements
		NodeList nl = docEle.getElementsByTagName("Utterance");
		if(nl != null && nl.getLength() > 0)
		{
			for(int i = 0 ; i < nl.getLength();i++)
			{
				//get the utterance element and remove stop words from its text content
				Element el = (Element)nl.item(i);
				String value = new String(" "+el.getTextContent()+" ");
				el.setTextContent(removeStopWords(value));
			}
		}
	}
	
	private void printData()
	{
		System.out.println("No of Utterances '" + utt.size() + "'.");

		Iterator<Utterance> it = utt.iterator();
		while(it.hasNext())
		{
			System.out.println(it.next().toString());
		}
	}
	
	/**
	 * This method uses Xerces specific classes
	 * prints the XML document to file.
     */
	private void printToFile(){

		try
		{
			//print
			OutputFormat format = new OutputFormat(dom);
			format.setIndenting(true);

			//to generate output to console use this serializer
			//XMLSerializer serializer = new XMLSerializer(System.out, format);

			//to generate a file output use fileoutputstream instead of system.out
			XMLSerializer serializer = new XMLSerializer(
			new FileOutputStream(new File(XML_OUTPUT_FILE)), format);

			serializer.serialize(dom);

		} catch(IOException ie) {
		    ie.printStackTrace();
		}
	}

}



